﻿using Orleans;
using Pay.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Pay.Model.Dto;
using System.Reflection;
using Pay.Model.Model;
using Pay.Core.exception;
using Pay.Dal;
using Pay.Container;
using Pay.Common;
using Pay.Common.Utilitys;
using Pay.Model;

namespace Pay.ServiceImplement
{
    public class PayService : Grain, IPayService
    {
        public async Task<PayOutput> CreatePayOrder(PayInput input)
        {
            if (input == null)
                throw new LotException("参数不能为空");

            if (DateTime.Now.ToUnixTimespan() - input.timespan > 60)
            {
                throw new LotException("接口请求超时,timespan必须在60秒内请求");
            }

            var paramCheck = input.Check();

            var serviceId = input.mch_code;

            if (paramCheck)
            {
                Dictionary<string, string> dic = new Dictionary<string, string>();
                foreach (PropertyInfo p in input.GetType().GetProperties())
                {
                    if (!string.IsNullOrWhiteSpace(p.GetValue(input).ToString()) && p.Name.ToLower() != "sign")
                    {
                        dic.Add(p.Name, p.GetValue(input).ToString());
                    }
                }
                var payDal = LocManager.Resolve<IPayDal>();

                // var service = GrainFactory.GetGrain<IAliaccountService>(serviceId);

                //根据商户code查询商户key
                var merchant = await payDal.GetMerchantByCode(input.mch_code);

                if (merchant == null)
                {
                    throw new LotException("商户信息错误");
                }

                //放入排序容器
                var pay = new AlipayModel();
                pay.PushData(dic);
                var isCheck = pay.Check(merchant.AccessKey, input.sign);

                if (!isCheck)
                {
                    throw new LotException("签名错误");
                }

                // 默认支付金额为提交请求时,发起的金额
                var amountPay = input.amount;

                var orderDal = LocManager.Resolve<IOrderDal>();

                // 生成订单id
                var orderId = IdUtil.NextId();

                // 激活时间,仅获取激活时间在10秒以内的支付宝账号
                var activeTime = DateTime.Now.AddSeconds(20);
#if DEBUG
                activeTime = DateTime.Parse("2018-08-07 00:00:00.00");
#endif

                // 验证客户提交的单号是否存在
                var mchOrderInfo = await payDal.GetOrderByMerchantTradeNo(merchant.Id, input.mch_trade_no);
                if (mchOrderInfo != null)
                {
                    // 每个商户相同的订单号只能有一个
                    throw new LotException($"订单号{input.mch_trade_no}已存在");
                }

                // 获取可用的支付宝集合
                var alipayAccouts = await payDal.GetAlipayAccountByMerchantId(merchant.Id, true, activeTime);
                if (alipayAccouts == null || alipayAccouts.Count == 0)
                {
                    // 平台用户没有对应支付宝账号
                    throw new LotException("支付宝账号读取失败");
                }

                // 支付宝轮询以id作为判定,每次使用比最后一次id大的支付宝账号,如果没有更大的id账号,则使用第一个,以此类推
                // 获取该商户下,上次使用支付宝的记录
                var lastOrder = await payDal.GetLastOrderByMerchantId(merchant.Id);

                // 获取该商户下挂起的订单(未完成支付的订单)
                var noCompletedOrders = await payDal.GetOrders(0, int.MaxValue, merchantId: merchant.Id, isCompleted: false, amount: amountPay);

                // 获取对应金额可用的支付宝二维码
                var qrcodes = await payDal.GetQrcodes(0, int.MaxValue, aliAccountId: alipayAccouts.Select(s => s.Id).ToArray(), amount: amountPay);

                // 正在使用的二维码
                var usingQrcodes = noCompletedOrders.Items.Select(o => o.OrderQrcodeDes).ToList();

                // 获取可以使用的二维码
                var okQrcode = qrcodes.Items.Where(s => !usingQrcodes.Contains(s.Description)).ToList();

                // 应用二维码
                var useQrcode = null as QRCodeInfo;

                // 应用支付宝
                var useAlipayAccount = null as AliAccountInfo;

                if (okQrcode == null || okQrcode.Count == 0)
                {
                    // 没有可用的收款码,使用金额为0的二维码完成交易
                    if (lastOrder == null)  // 如果没有最后一次交易信息,使用默认第一个账号完成该笔交易
                    {
                        useAlipayAccount = alipayAccouts.FirstOrDefault();
                    }
                    else
                    {
                        useAlipayAccount = alipayAccouts.FirstOrDefault(s => s.Id > lastOrder.OrderAlipayAccountId);
                        if (useAlipayAccount == null)
                        {
                            useAlipayAccount = alipayAccouts.FirstOrDefault();
                        }
                    }
                }
                else
                {
                    // 有可用收款码的时候,使用可用的二维码支付
                    if (lastOrder == null) // 如果没有最后一次交易信息,使用默认第一个二维码完成该笔交易
                    {
                        useQrcode = qrcodes.Items.FirstOrDefault();
                    }
                    else // 如果存在最后一笔交易信息,则使用比上一次id大的二维码进行交易,如果没有,使用第一个
                    {
                        useQrcode = qrcodes.Items.FirstOrDefault(s => s.Id > lastOrder.OrderQrcodeId);
                        if (useQrcode == null)
                        {
                            useQrcode = qrcodes.Items.FirstOrDefault();
                        }
                    }

                    // 通过二维码找到支付宝账号
                    useAlipayAccount = alipayAccouts.FirstOrDefault(s => s.Id == useQrcode.AliAccountId);
                }

                if (useAlipayAccount == null)
                {
                    // 正常逻辑下,不会进入该判断,防止以后因其他业务插入导致异常
                    throw new LotException("支付宝账号异常");
                }

                if (useQrcode == null)
                {
                    // 如果使用的二维码是空,表示目前没有可用的二维码金额,此时应用第二种流程
                    // 根据支付金额逐步增加0.01分
                    // 找到金额为0的二维码
                    var qrcodes2 = await payDal.GetQrcodes(0, int.MaxValue, aliAccountId: new long[] { useAlipayAccount.Id }, amount: 0);
                    if (qrcodes2 == null || qrcodes2.Items == null || qrcodes2.Items.Count == 0)
                    {
                        throw new LotException("二维码读取失败");
                    }

                    useQrcode = qrcodes2.Items.FirstOrDefault();

                    // 从挂起的订单中找到该二维码最大的支付金额
                    var usealipayLastOrder = noCompletedOrders.Items.Where(s => s.OrderAlipayAccountId == useAlipayAccount.Id && s.OrderQrcodeDes == useQrcode.Description).OrderByDescending(s => s.AmountPay).FirstOrDefault();

                    if (usealipayLastOrder != null) // 如果该支付宝下没有存在挂起的支付订单,直接使用提交请求的金额,否则金额每次增加0.01
                    {
                        amountPay = usealipayLastOrder.AmountPay + 0.01m;
                    }

                    // 暂时弃用手动输入金额
                    throw new LotException("二维码异常");
                }

                var ids = alipayAccouts.Select(c => c.Id).ToArray();

                var now = DateTime.Now;

                // 生成订单  状态未支付
                var order = new OrderInfo()
                {
                    Id = orderId, // TradeNo 订单id作为流水号
                    MerchantId = merchant.Id,
                    IsCompleted = false,
                    Amount = input.amount,
                    AmountPay = amountPay,
                    FeeAmount = input.amount * merchant.FeeRate,
                    FeeRate = merchant.FeeRate,
                    MchNotifyUrl = input.notify_url,
                    MchParam = input.param,
                    MchReturnUrl = input.return_url,
                    MchTradeNo = input.mch_trade_no,
                    OrderAlipayAccountId = useAlipayAccount.Id,
                    OrderAlipayAccount = useAlipayAccount.AccountName,
                    OrderSystemAccount = useAlipayAccount.SystemAccount,
                    OrderQrcodeId = useQrcode.Id,
                    OrderQrcodeDes = useQrcode.Description,
                    OrderQrcodeUrl = useQrcode.QRcodeUrl,
                    PayType = Model.Enums.PayType.Alipay,
                    PayStatus = Model.Enums.AlipayOrderStatus.UnPaid,
                    CreateTime = now,
                    LastModifyTime = now,
                    ExpireTime = now.AddMinutes(5) // 订单过期时间为5分钟
                };
                await payDal.CreateOrder(order);

                throw new LotException("未完待续");

            }
            return new PayOutput();
        }
    }
}